<?php
declare(strict_types=1);

namespace lib\data;

use lib\data\virtual\GoodsOrder;
use sys\Db;
use sys\Log;
use sys\SqlBuilder;

class Components extends \lib\sync\SyncableData {
    use traits\ComponentsTrait;
    use traits\WaitLock;

    const PROP_COUNTOFF = 0;        # 计入库存
    const PROP_COUNTON  = 1;        # 不计入库存
    const PROP_MATERIAL = 2;        # 原材料

    protected static string $TableName = 'el_components';
    protected static string $SyncKey = 'Component';
    
    protected int $id;
    protected int $mid;
    protected array $category_ids;
    protected string $name;         # 名称
    protected string $model;        # 元件型号
    protected string $brand;        # 品牌
    protected string $pack;         # 封装
    protected string $tolerance;     # 精度
    protected string $voltage;       # 耐压范围
    protected string $temperature;   # 工作温度范围
    protected int $createtime;
    protected int $sortid;

    protected static array $propNamesC = ['id','mid','category_ids', 'name', 'model', 'brand', 'pack', 'tolerance', 'voltage', 'temperature', 'createtime', 'sortid'];
    protected static array $propNamesU = ['id','mid','category_ids', 'name', 'model', 'brand', 'pack', 'tolerance', 'voltage', 'temperature', 'createtime', 'sortid'];
    protected static array $propNamesJ = ['id','mid','category_ids', 'name', 'model', 'brand', 'pack', 'tolerance', 'voltage', 'temperature', 'createtime', 'sortid'];

    public function __construct(array &$data)
    {
        parent::__construct($data);
        $this->traitInit();
    }


    public static function Move(int $mid , int $fromId, int $toId) :array {
        $from = \lib\data\Components::get($fromId);
        $to = \lib\data\Components::get($toId);

        if(null === $from || null === $to){
            return ['success'=>false, 'message'=>'商品不存在.'];
        }

        if($from->id === $to->id){
            return ['success'=>false, 'message'=>'不能移动到自己.'];
        }

        if($from->mid !== $mid || $to->mid !== $mid){
            return ['success'=>false, 'message'=>'商品不存在.'];
        }

        $toSortId = $to->sortid;
        $moveFront = $from->sortid > $toSortId;
        $syncObject = new \lib\sync\Synchronize($mid);
        $db = new \sys\Db();
        $db->startTrans();
        try{
            $db->table('el_components')->where([['id', '=', $from->id]])->lock(true)->field('id')->find();
            if($moveFront){
                # 前移
                $moves= array_column($db->table('el_components')->where([['mid', '=', $mid], ['sortid', 'BETWEEN', [$toSortId, $from->sortid-1]]])->lock(true)->field('id')->select() ?? [], 'id');
                $sqls = [
                    $db->table('el_components')->where([['mid', '=', $mid], ['sortid', 'BETWEEN', [$toSortId, $from->sortid-1]]])->inc('sortid', 1)->subUpdate(),
                    $db->table('el_components')->where([['id', '=', $from->id]])->subUpdate(['sortid'=>$toSortId]),
                ];
            }else{
                # 后移
                $moves= array_column($db->table('el_components')->where([['mid', '=', $mid], ['sortid', 'BETWEEN', [$from->sortid+1, $toSortId]]])->lock(true)->field('id')->select() ?? [], 'id');
                $sqls = [
                    $db->table('el_components')->where([['mid', '=', $mid], ['sortid', 'BETWEEN', [$from->sortid+1, $toSortId]]])->dec('sortid', 1)->subUpdate(),
                    $db->table('el_components')->where([['id', '=', $from->id]])->subUpdate(['sortid'=>$toSortId]),
                ];
            }
            $db->batch_query($sqls, \sys\Db::SQL_UPDATE);
            $db->commit();

            if($moveFront){
                # 前移
                foreach($moves as $id){
                    $gds = static::get($id);
                    $gds->sortid += 1;
                    $syncObject->up('Goods', $gds->id, ['sortid'=>$gds->sortid]);
                }
            }else{
                # 后移
                foreach($moves as $id){
                    $gds = static::get($id);
                    $gds->sortid -= 1;
                    $syncObject->up('Goods', $gds->id, ['sortid'=>$gds->sortid]);
                }
            }
            $from->sortid = $toSortId;
            $syncObject->up('Goods', $from->id, ['sortid'=>$from->sortid]);
            \lib\Merchant::get($mid)->push(['event'=>'sync','data'=>$syncObject->makeSyncData($db)]);
            return ['success'=>true, 'message'=>'调整成功.'];
        }catch(\Exception $e){
            $db->rollback();
            return ['success'=>false, 'message'=>$e->getMessage()];
        }
    }

    static protected function buildSyncSelect(Db $db, int $mid, int $time, int $lastId = 0): SqlBuilder
    {
        $sql = $db->table('el_components')->order('el_components.id ASC');

        if(0 == $lastId){
            return $sql->where(['mid', '=', $mid]);
        }
        return $sql->where([
            ['id','>', $lastId],
            ['mid', '=', $mid],
        ]);
    }

    public static function GoodsRemove(\lib\Merchant $m, int $uid, int $id) : array{
        $tasks = [];
        $rmStoreComponents = [];
        $objectCached = [];
        $mid = $m->id;
        $operator_uid = $uid;

        if(null === ($goods = static::get((int)$id)) || $goods->mid != $mid){
            return [
                'success'=>false,
                'message'=>'商品不存在'
            ];
        }
        $isNew = false;
        $merchant = $m->waitLock();
        $time = time();

        $db = new \sys\Db();
        $stores = \lib\data\Store::getAll($mid);

        foreach($stores as $store){
            if(null !== ($StoreComponents = StoreComponents::getGoodsFromStoreId($store->id, $goods->id, $isNew, null)) && $StoreComponents->store_num > 0){
                $rmStoreComponents[] = $StoreComponents->waitLock();
            }
        }

        if(count($rmStoreComponents) > 0){
            $document_no = \lib\Utils::genOrderNo('RG');
            $tasks[] = $tp_nb_goods_documents = $db->task('tp_nb_goods_documents')->subInsert([
                'mid'           => $mid,
                'document_no'   => $document_no,
                'document_type' => StoreComponents::DOC_TYPE_GOODS_ARRANGE,
                'shift_id'      => $merchant->shift_id,
                'operator_uid'  => $operator_uid,
                'settle_mode'   => GoodsOrder::SETTLE_MODE_NOPAY,
                'order_id'      => 0,
                'order_type'    => 256,
                'amount'        => 0,
                'realpay'       => 0,
                'desc'          => '删除商品',
                'createtime'    => $time,
            ]);
            
            $doc_id = new \sys\db\ExpValue($tp_nb_goods_documents->pkVarName());

            foreach($rmStoreComponents as $StoreComponents){
                $tasks[] = # 商品变化记录
                $tasks[] = $db->task('el_components_changes')->subInsert([
                    'mid'               => $mid,
                    'shift_id'          => $merchant->shift_id,
                    'document_id'       => $doc_id,
                    'document_type'     => StoreComponents::DOC_TYPE_GOODS_ARRANGE,
                    'operator_uid'      => $operator_uid,
                    'goods_id'          => $goods->id,
                    'goods_name'        => $goods->name,
                    'settle_mode'       => GoodsOrder::SETTLE_MODE_NOPAY,
                    'store_id'          => $StoreComponents->store_id,
                    'store_name'        => $store->name,
                    'store_before'      => $StoreComponents->store_num,
                    'num'               => -$StoreComponents->num,
                    'store_after'       => 0,
                    'target_id'         => 0,
                    'target_name'       => '',
                    'target_before'     => 0,
                    'target_after'      => 0,
                    'calc_mode'         => StoreComponents::CALC_MODE_PIECE,
                    'pack_size'         => $goods->pack_size,               # 每件个数
                    'pack_num'          => 0,                               # 多少件
                    'amount'            => 0,                               # 计算好的价格. 如果是赠送 该项为0
                    'createtime'        => $time,
                ]);
                $StoreComponents->remove();
                $tasks[] = $db->table('tp_nb_goods_store_map')->where(['id','=', $StoreComponents->id])->subDelete();
                $objectCached[] = $StoreComponents;
            }
        }

        $tasks[] = $db->table('el_components')->where(['id','=', $goods->id])->subDelete();
        $objectCached[] = $goods;

        $db->startTrans();
        try{
            $rawGoods = $db->table('el_components')->where(['id','=', $goods->id])->find();
            if($db->batch_execute($tasks)){
                $db->commit();
                
                # 是私有照片, 删除
                if(!empty($rawGoods['img'])){
                    \lib\ExtiStorage::delete($rawGoods['img']);
                }

                $syncObject = new \lib\sync\Synchronize($mid, $db);
                foreach($objectCached as $o){
                    $o->remove();
                    $syncObject->rm($o->getSyncName(), $o->id);
                }
                return ['success'=>true, 'message'=>'删除成功.'];
            }
            $db->rollback();
        }catch(\Exception $e){
            $db->rollback();
            Log::write(implode([$e->getMessage(),"\nFILE: ", $e->getFile(), "\nLINE: ", $e->getLine(),"\nTRACE: ", $e->getTraceAsString(),"\n"]),'ERROR');
        }
        return ['success'=>false, 'message'=>'删除失败.'];
    }
}